import io
import time

from components.VolumeInfo import VolumeInfo
from components.dicom_tag_info import DicomTagInfo
from layers.BaseImgLayer import BaseImgLayer
from layers.CrossLayer import CrossLayer
from layers.InfoLayer import InfoLayer
from layers.NewMeasureLayer import NewMeasureLayer
from layers.PerformanceMeasureLayer import PerformanceMeasureLayer
from utils.util import compose_img, img_to_png_base64, img_to_jpeg_base64
from type import EnumImgQuality, EnumViewType,EnumImgMode


def convert_bytes(image, img_quality):
    with io.BytesIO() as output_bytes:
        if img_quality == EnumImgQuality.high.value:
            image.save(output_bytes, format="PNG", quality=100)
        else:
            image.save(output_bytes, format="JPEG", quality=50)
        img_bytes = output_bytes.getvalue()
    return img_bytes


def img_to_base64(bytes, img_quality):
    if img_quality == EnumImgQuality.high.value:
        return img_to_png_base64(bytes)
    else:
        return img_to_jpeg_base64(bytes)


class Viewer:
    def __init__(self, view_type, dicom_tag_info: DicomTagInfo, volume_info):
        self.dicom_tag_info = dicom_tag_info
        self.view_type = view_type
        self.volume_info: VolumeInfo = volume_info
        self.base_img_layer = BaseImgLayer(view_type, dicom_tag_info, volume_info=volume_info)  # 基础图像
        self.info_layer = InfoLayer(view_type=self.view_type,
                                    dicom_tag_info=dicom_tag_info, volume_info=self.volume_info)  # 四角信息
        self.cross_layer = CrossLayer(view_type, volume_info=volume_info)
        self.measure_layer = NewMeasureLayer(view_type, dicom_tag_info, volume_info)
        self.performance_layer = PerformanceMeasureLayer(view_type, dicom_tag_info, volume_info)
        self.mode: EnumImgMode = EnumImgMode.img.value

    def toggle_mode(self, new_mode: EnumImgMode):
        self.mode = new_mode

    def get_mix_img(self, img_quality=EnumImgQuality.high.value):
        dicom_data = self.volume_info.get_current_dicom_data(self.view_type)
        return self.get_mix_img_by_dicom_data(dicom_data, img_quality)

    def get_mix_img_by_dicom_data(self, dicom_data, img_quality=EnumImgQuality.high.value):
        base_layer_arr = self.base_img_layer.get_base_img_arr(dicom_data)
        info_layer_arr = self.info_layer.get_info_layer()
        return self.get_mix_img_by_view_type(base_layer_arr, info_layer_arr, img_quality)

    def get_mix_img_by_view_type(self, base_layer_arr, info_layer_arr, img_quality=EnumImgQuality.high.value):
        match (self.view_type, self.mode):
            case (EnumViewType.Stack.value, EnumImgMode.img.value):
                other_layer = self.measure_layer.get_layer()
                mix_rgba_img = compose_img(base_layer_arr, other_layer)

                img_bytes = convert_bytes(mix_rgba_img, img_quality)

                base64_img = img_to_base64(img_bytes, img_quality)

                current, total = self.get_slice_info()
                current_phase, total_phase = self.get_phase_info()

                return {
                    "img": base64_img,
                    "info_layer": info_layer_arr,
                    "slice_info": {
                        "current": current,
                        "total": total,
                    },
                    "phase_info": {
                        "current": current_phase,
                        "total": total_phase
                    },
                }
            case (EnumViewType.Stack.value, EnumImgMode.performance.value):
                other_layer, mtf_dict = self.performance_layer.get_layer()
                mix_rgba_img = compose_img(base_layer_arr, other_layer)

                img_bytes = convert_bytes(mix_rgba_img, img_quality)

                base64_img = img_to_base64(img_bytes, img_quality)

                current, total = self.get_slice_info()
                current_phase, total_phase = self.get_phase_info()

                return {
                    "img": base64_img,
                    "info_layer": info_layer_arr,
                    "slice_info": {
                        "current": current,
                        "total": total,
                    },
                    "phase_info": {
                        "current": current_phase,
                        "total": total_phase
                    },
                    "mtf_dict": mtf_dict
                }
            case (EnumViewType.Sag.value, _) | (EnumViewType.Ax.value, _) | (EnumViewType.Cor.value, _):
                center, h_color, v_color, mip = self.cross_layer.get_layer()
                other_layer = self.measure_layer.get_layer()

                mix_rgba_img = compose_img(base_layer_arr, other_layer)

                img_bytes = convert_bytes(mix_rgba_img, img_quality)

                base64_img = img_to_base64(img_bytes, img_quality)

                current, total = self.get_slice_info()
                current_phase, total_phase = self.get_phase_info()

                return {
                    "img": base64_img,
                    "center": {
                        "position": center,
                        "color": {
                            "h_color": h_color,
                            "v_color": v_color,
                        },
                        "mip": mip
                    },
                    "info_layer": info_layer_arr,
                    "slice_info": {
                        "current": current,
                        "total": total,
                    },
                    "phase_info": {
                        "current": current_phase,
                        "total": total_phase
                    },
                }

    def get_slice_info(self):
        current, total = self.volume_info.get_origin_current_total(self.view_type)
        return current + 1, total

    def get_phase_info(self):
        current = self.volume_info.phase_data.current
        total = self.volume_info.phase_data.total
        return current, total

    def get_current_mouse_position(self, png_x, png_y):
        origin_dicom_position = self.volume_info.screen_position_to_clipped_voxel_position(self.view_type, png_x,
                                                                                           png_y)
        hu_value = self.base_img_layer.get_hu_value_by_position(origin_dicom_position)
        self.info_layer.update_point_value((origin_dicom_position[0] + 1, origin_dicom_position[1] + 1, hu_value))

    def get_recent_img(self, img_quality=EnumImgQuality.low.value):
        dicom_data = self.volume_info.get_current_dicom_data(view_type=self.view_type)
        ans = self.get_mix_img_by_dicom_data(dicom_data, img_quality)
        return ans

    def update_flip(self, hor_flip, ver_flip):
        self.volume_info.transform_viewport_flip(self.view_type, hor_flip, ver_flip)
        if hor_flip:
            self.info_layer.hor_flip_direction()
        if ver_flip:
            self.info_layer.ver_flip_direction()

    def update_rotate(self, rotate_type):
        angle = 90
        if rotate_type == 'CW90':
            clockwise = True
            self.info_layer.rotate_direction(-90)
        else:
            clockwise = False
            self.info_layer.rotate_direction(90)
        self.volume_info.transform_viewport_rotate(self.view_type, clockwise, angle)

    def update_window(self, delta_x, delta_y):
        self.volume_info.set_transfer_info_window(self.view_type, delta_x, delta_y)

    def update_zoom(self, zoom_factor):
        self.volume_info.transform_viewport_zoom(self.view_type, zoom_factor)

    def update_pan(self, delta_x, delta_y):
        self.volume_info.transform_viewport_pan(self.view_type, delta_x, delta_y)

    def update_current_slice(self, scroll):
        new_slice_flag = False
        if scroll > 0:
            new_slice_flag = self.volume_info.set_next_slice(self.view_type)
        elif scroll < 0:
            new_slice_flag = self.volume_info.set_prev_slice(self.view_type)
        return new_slice_flag

    def slice_to_index(self, to_index):
        self.volume_info.set_slice_index(self.view_type, to_index - 1)

    def handle_draw(self, sub_op_type, position, action_type):
        if self.mode == EnumImgMode.img.value:
            self.measure_layer.handle_mouse_op(action_type, position, sub_op_type)
        elif self.mode == EnumImgMode.performance.value:
            self.performance_layer.handle_mouse_op(action_type, position, sub_op_type)

    def reset(self, reset_type):
        match reset_type:
            case 'resetWindow':
                self.reset_window()
            case 'resetMeasure':
                self.reset_measure()
            case 'resetZoom':
                pass
            case 'resetCross':
                pass
            case 'resetAll':
                self.reset_all()
                pass

    def reset_window(self):
        self.volume_info.init_window(self.view_type)

    def reset_measure(self):
        self.measure_layer.clear_measure()

    def reset_pan(self):
        pass

    def reset_zoom(self):
        pass

    def reset_cross(self):
        pass

    def reset_all(self):
        self.reset_window()
        self.reset_measure()
        self.volume_info.init_transform_matrix(self.view_type)

    def update_resize(self, size):
        self.volume_info.resize(self.view_type, size)
        self.measure_layer.resize()

